package com.fansl.allround.auth.service;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.fansl.allround.common.core.bean.UserInfo;
import com.fansl.allround.common.core.constant.CacheConstants;
import com.fansl.allround.common.core.constant.CommonConstants;
import com.fansl.allround.common.core.constant.SecurityConstants;
import com.fansl.allround.common.core.constant.enums.OauthTypeEnum;
import com.fansl.allround.common.security.service.AllroundSysUser;
import com.fansl.allround.common.security.service.AllroundUserDetailsService;
import com.fansl.allround.upms.api.entity.SysUser;
import com.fansl.allround.upms.api.feign.RemoteUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * @author fansl
 * @Description: TODO
 * @date 2019/7/15 14:27
 */
@Slf4j
@Service
@AllArgsConstructor
@Primary
public class SysUserDetailsServiceImpl implements AllroundUserDetailsService {
    private final RemoteUserService remoteUserService;
    private final CacheManager cacheManager;

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Cache cache = cacheManager.getCache(CacheConstants.CACHE_USER_DETAIL);
        if (cache != null && cache.get(username) != null) {
            Object cacheObj = cache.get(username).get();
            return (AllroundSysUser) cacheObj;
        }

        UserInfo userInfo = remoteUserService.info(username, SecurityConstants.FROM_IN);
        UserDetails userDetails = getUserDetails(userInfo);
        cache.put(username, userDetails);
        return userDetails;
    }

    /**
     * 根据认证类型获取用户信息
     *
     * @param oauthName 认证内容
     * @param oauthType 认证类型
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByOauthType(String oauthName, OauthTypeEnum oauthType) throws UsernameNotFoundException {
        UserInfo userInfo = null;
        switch (oauthType) {
            case PHONE:
                userInfo = remoteUserService.mobile(oauthName, SecurityConstants.FROM_IN);
                break;
            case PASSWORD:
                return loadUserByUsername(oauthName);
            case WEIBO:
            case QQ:
            case WECHAT:
                userInfo = remoteUserService.social(oauthName, oauthType, SecurityConstants.FROM_IN);
                break;
            default:
        }
        return getUserDetails(userInfo);
    }

    /**
     * 构建userdetails
     *
     * @param userInfo 用户信息
     * @return
     */
    @Override
    public UserDetails getUserDetails(UserInfo userInfo) {
        if (userInfo == null || userInfo.getUser() == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        Set<String> dbAuthSet = new HashSet<>();
        if (ArrayUtil.isNotEmpty(userInfo.getRoles())) {
            //获取角色
            Arrays.stream(userInfo.getRoles()).forEach(role -> dbAuthSet.add(SecurityConstants.ROLE + role));
            //获取资源
            dbAuthSet.addAll(Arrays.asList(userInfo.getPermissions()));
        }
        Collection<? extends GrantedAuthority> authorities =
                AuthorityUtils.createAuthorityList(dbAuthSet.toArray(new String[0]));
        SysUser user = JSONObject.parseObject(JSONObject.toJSONString(userInfo.getUser()),
                SysUser.class);
        //构造security用户
        AllroundSysUser allroundSysUser = new AllroundSysUser(user.getUserId(), user.getDeptId(), user.getUsername(), SecurityConstants.BCRYPT + user.getPassword(),
                StrUtil.equals(user.getLockFlag(), CommonConstants.STATUS_NORMAL), true, true, true, authorities);
        return allroundSysUser;
    }
}
